package client;

/**
 * Controller of client. Coordinate what to do. Subdivide work to other
 * components.
 * 
 * @author papq
 */
public class Controller implements Observer, Notificable {
	public Model model;
	public MainViewJFrame mainView;
	public StartViewJFrame startView;
	private Core core;

	/**
	 * @author papq Method which allows controller to control other classes.
	 */
	public Controller() {
		this.model = new Model();
		this.mainView = new MainViewJFrame(model);
		this.startView = new StartViewJFrame(model);
		this.core = new Core();
		startView.addObserver(this);
		mainView.addObserver(this);
		startView.setVisible(true);
	}

	/**
	 * Method which launch if server send message.
	 * 
	 * @param receivedMessage
	 *            content of message received from server.
	 */
	public void messageReceived(String receivedMessage) {
		try {
			core.getMessage((Notificable) this);
			model.setOperationCode(core.checkOperationCode(receivedMessage));

			System.out.println("aaa New received Message: " + receivedMessage);
			switch (model.getOperationCode()) {
			case "02":
				//asking player to start game
				if (receivedMessage.substring(8, 10).equals("ST")) {
					startView.askForStartGame();
				} else {
					model.setText(core.getMessageToDisplay());
					startView.displayMessage();
				}
				break;
			case "03":
				System.out.println("New hand: " + receivedMessage);
				// transfer of the cards.
				// Content: ColourOfTheCard,ValueOfTheCard/C,V/C,V/C,V;
				// example: <2><03><1,7/4,11/3,8/2,10>
				model.setHand(core.getParameters());
				mainView.setHand();
				mainView.displayMessage("Cards exchanged. You have new card(s) now.");
				break;
			case "04":
				// who has: dealer button, small blind, big blind
				// Content:
				// IDPlayerWithDealerButtonNow,IDPlayerWithSmallBlindNow,IDPlayerWithBigBlindNow
				// example: <2><04><0,1,2>
				System.out.println("<04> dealer button: " + receivedMessage);
				model.setDealer(receivedMessage.substring(8, 9));
				model.setWhoHasSmallBlind(receivedMessage.substring(10, 11));
				model.setWhoHasBigBlind(receivedMessage.substring(12, 13));
				model.setMaxBetNow(model.getBigBlind());
				mainView.displayMaxBet();
				// System.out.println("dealer: " + model.getDealer());
				// System.out.println("big blind: " +
				// model.getWhoHasBigBlind());
				// System.out.println("small blind: " +
				// model.getWhoHasSmallBlind());
				if (model.getWhoHasBigBlind().equals(model.getPlayerID())) {
					mainView.displayPlayerBetNowAndBankrollNow();
				} else if (model.getWhoHasSmallBlind().equals(
						model.getPlayerID())) {
					mainView.displayPlayerBetNowAndBankrollNow();
				}
				mainView.setDealer(model.getDealer());
				mainView.setWhoHasBigBlind(model.getWhoHasBigBlind());
				mainView.setWhoHasSmallBlind(model.getWhoHasSmallBlind());
				startView.setVisible(false);
				mainView.setVisible(true);
				break;
			case "05":
				// Betting
				System.out.println("BettingRound: " + receivedMessage);
				switch(receivedMessage.substring(8, 10)) {
				case "ST":
					model.setBettingRound(receivedMessage);
					System.out.println("BettingRound: "
							+ model.getBettingRound());
					switch (model.getBettingRound()) {
					case "0":
						mainView.displayMessage("First betting round has started. Wait for your turn.");
						break;
					case "1":
						mainView.displayMessage("Second betting round has started. Wait for your turn.");
						break;
					case "2":
						mainView.displayMessage("Third betting round has started. Wait for your turn.");
						break;
					case "3":
						mainView.displayMessage("Last betting round has started. Wait for your turn.");
						break;
					}
					break;
				case "WD":
					switch (model.getBettingRound()) {
					case "0":
						mainView.displayMessage("First betting round. Choose option to bet.");
						mainView.enableBettingButtons();
						break;
					case "1":
						mainView.displayMessage("Second betting round. Choose option to bet.");
						mainView.enableBettingButtons();
						break;
					case "2":
						mainView.displayMessage("Third betting round. Choose option to bet.");
						mainView.enableBettingButtons();
						break;
					case "3":
						mainView.displayMessage("Last betting round. Choose option to bet.");
						mainView.enableBettingButtons();
						break;
					}
					break;
//					Message with action of active player; it will be sent to all Clients.
				case "CH":
					model.setIDOfPlayerWhoPlayed(receivedMessage.substring(11, 12));
					if (model.getPlayerID().equals(model.getIDOfPlayerWhoPlayed())) {
						mainView.setMenuPanelAfterBetting();
						mainView.displayMessage("You played \"Check\".");
						System.out.println("aaa You played \"Check\".");
					} else {
						mainView.setPanelPlayerWhoPlayed("Check");
						mainView.displayMessage("Player " + model.getIDOfPlayerWhoPlayed() + " played \"Check\".");
						System.out.println("aaa Player " + model.getIDOfPlayerWhoPlayed() + " played \"Check\".");
					}
					break;
				case "BE":
					model.setIDOfPlayerWhoPlayed(receivedMessage.substring(11, 12));
					model.setBetValueOfPlayerWhoPlayed(receivedMessage.split(",")[2]);
					model.setBankrollOfPlayerWhoPlayed(receivedMessage.split(",")[3]);
					model.setWasBetPlayed(true);
					if (model.getWhoHasSmallBlind().equals(model.getIDOfPlayerWhoPlayed())) {
						model.setMaxBetNow(Integer.toString(model.getBetValueOfPlayerWhoPlayed() + Integer.parseInt(model.getSmallBlind())));
					} else if (model.getWhoHasBigBlind().equals(model.getIDOfPlayerWhoPlayed())) {
						model.setMaxBetNow(Integer.toString(model.getBetValueOfPlayerWhoPlayed() + Integer.parseInt(model.getBigBlind())));
					} else {
						model.setMaxBetNow(Integer.toString(model.getBetValueOfPlayerWhoPlayed()));
					}
					System.out.println("aaa NEW MAX BET: " + model.getMaxBetNow());
					if (model.getPlayerID().equals(model.getIDOfPlayerWhoPlayed())) {
						if (model.getWhoHasSmallBlind().equals(model.getPlayerID())) {
							model.setPlayerBetNow(Integer.toString(model.getBetValueOfPlayerWhoPlayed() + Integer.parseInt(model.getSmallBlind())));
						} else if (model.getWhoHasBigBlind().equals(model.getPlayerID())) {
							model.setPlayerBetNow(Integer.toString(model.getBetValueOfPlayerWhoPlayed() + Integer.parseInt(model.getBigBlind())));
						} else {
							model.setPlayerBetNow(Integer.toString(model.getBetValueOfPlayerWhoPlayed()));
						}
						model.setPlayerBankrollNow(Integer.parseInt(model.getBankrollOfPlayerWhoPlayed()));
						mainView.setMenuPanelAfterBetting();
						mainView.displayMessage("You played \"Bet\".");
						System.out.println("aaa You played \"Bet\".");
					} else {
						mainView.setPanelPlayerWhoPlayed("Bet");
						mainView.displayMessage("Player " + model.getIDOfPlayerWhoPlayed() + " played \"Bet\".");
						System.out.println("aaa Player " + model.getIDOfPlayerWhoPlayed() + " played \"Bet\".");
					}
					mainView.displayMaxBet();
					//disable betButton
					//enable raiseButton 
					break;
				case "RA":
					model.setIDOfPlayerWhoPlayed(receivedMessage.substring(11, 12));
					model.setBetValueOfPlayerWhoPlayed(receivedMessage.split(",")[2]);
					model.setBankrollOfPlayerWhoPlayed(receivedMessage.split(",")[3]);
					model.setWasRaisePlayed(true);
					if (model.getWhoHasSmallBlind().equals(model.getIDOfPlayerWhoPlayed())) {
						model.setMaxBetNow(Integer.toString(model.getBetValueOfPlayerWhoPlayed() + Integer.parseInt(model.getSmallBlind())));
					} else if (model.getWhoHasBigBlind().equals(model.getIDOfPlayerWhoPlayed())) {
						model.setMaxBetNow(Integer.toString(model.getBetValueOfPlayerWhoPlayed() + Integer.parseInt(model.getBigBlind())));
					} else {
						model.setMaxBetNow(Integer.toString(model.getBetValueOfPlayerWhoPlayed()));
					}
					System.out.println("aaa NEW MAX BET: " + model.getMaxBetNow());
					if (model.getPlayerID().equals(model.getIDOfPlayerWhoPlayed())) {
						if (model.getWhoHasSmallBlind().equals(model.getPlayerID())) {
							model.setPlayerBetNow(Integer.toString(model.getBetValueOfPlayerWhoPlayed() + Integer.parseInt(model.getSmallBlind())));
						} else if (model.getWhoHasBigBlind().equals(model.getPlayerID())) {
							model.setPlayerBetNow(Integer.toString(model.getBetValueOfPlayerWhoPlayed() + Integer.parseInt(model.getBigBlind())));
						} else {
							model.setPlayerBetNow(Integer.toString(model.getBetValueOfPlayerWhoPlayed()));
						}
						model.setPlayerBankrollNow(Integer.parseInt(model.getBankrollOfPlayerWhoPlayed()));
						mainView.setMenuPanelAfterBetting();
						mainView.displayMessage("You played \"Raise\".");
						System.out.println("aaa You played \"Raise\".");
					} else {
						mainView.setPanelPlayerWhoPlayed("Raise");
						mainView.displayMessage("Player " + model.getIDOfPlayerWhoPlayed() + " played \"Raise\".");
						System.out.println("aaa Player " + model.getIDOfPlayerWhoPlayed() + " played \"Raise\".");
					}
					mainView.displayMaxBet();
					mainView.setPotPanelAfterAction();
					break;
				case "CA":
					model.setIDOfPlayerWhoPlayed(receivedMessage.substring(11, 12));
					model.setBankrollOfPlayerWhoPlayed(receivedMessage.split(",")[3]);
//					System.out.println("aaa Bankroll OfPlayerWhoPlayed \"Call\": " + model.getBankrollOfPlayerWhoPlayed());
					if (model.getPlayerID().equals(model.getIDOfPlayerWhoPlayed())) {
						model.setPlayerBetNow(Integer.toString(model.getMaxBetNow()));
						model.setPlayerBankrollNow(Integer.parseInt(model.getBankrollOfPlayerWhoPlayed()));
						mainView.setMenuPanelAfterBetting();
						mainView.displayMessage("You played \"Call\".");
						System.out.println("aaa You played \"Call\".");
					} else {
						mainView.setPanelPlayerWhoPlayed("Call");
						mainView.displayMessage("Player " + model.getIDOfPlayerWhoPlayed() + " played \"Call\".");
						System.out.println("aaa Player " + model.getIDOfPlayerWhoPlayed() + " played \"Call\".");
					}
					break;
				case "FO":
					model.setIDOfPlayerWhoPlayed(receivedMessage.substring(11, 12));
					if (model.getPlayerID().equals(model.getIDOfPlayerWhoPlayed())) {
						mainView.setMenuPanelAfterBetting();
						mainView.displayMessage("You played \"Fold\".");
						System.out.println("aaa You played \"Fold\".");
					} else {
						mainView.setPanelPlayerWhoPlayed("Fold");
						mainView.displayMessage("Player " + model.getIDOfPlayerWhoPlayed() + " played \"Fold\".");
						System.out.println("aaa Player " + model.getIDOfPlayerWhoPlayed() + " played \"Fold\".");
					}
					break;
				case "AL":
					model.setIDOfPlayerWhoPlayed(receivedMessage.substring(11, 12));
					model.setBetValueOfPlayerWhoPlayed(receivedMessage.split(",")[2]);
					//bankroll should be 0 instead of being equal to betvalueofplayerwhoplayed
//					System.out.println("aaa Bet Value OfPlayerWhoPlayed \"Call\": " + model.getBetValueOfPlayerWhoPlayed());
//					System.out.println("aaa Bankroll OfPlayerWhoPlayed \"Call\": " + model.getBankrollOfPlayerWhoPlayed());
					if (model.getPlayerID().equals(model.getIDOfPlayerWhoPlayed())) {
						model.setPlayerBetNow(Integer.toString((model.getBetValueOfPlayerWhoPlayed()+model.getPlayerBetNow())));
						model.setPlayerBankrollNow(0);
						mainView.setMenuPanelAfterBetting();
						mainView.displayMessage("You played \"All-in\".");
						System.out.println("aaa You played \"All-in\".");
					} else {
						mainView.setPanelPlayerWhoPlayed("All-in");
						mainView.displayMessage("Player " + model.getIDOfPlayerWhoPlayed() + " played \"All-in\".");
						System.out.println("aaa Player " + model.getIDOfPlayerWhoPlayed() + " played \"All-in\".");
					}
					break;
				}
				break;
			case "07":
				//Changing - QUESTIONS of ROOM and messages of the ROOM.
				System.out.println("Exchange: " + receivedMessage);
				switch(receivedMessage.substring(8, 10)) {
				case "ST":
					mainView.displayMessage("Card exchange has started. Wait for your turn.");
					break;
				case "WD":
					mainView.displayMessage("Card exchange. Choose cards to exchange and click \"EXCHANGE\".");
					mainView.enableCardsExchange();
					break;
				default:
//					displays how many cards has another player changed
//					Message with action of active player; it will be sent to all Clients.
//					<RoomID><07><NrOfChangingCards,IDOfPlayer>
					model.setPlayerIDWhoExchanged(receivedMessage);
					model.setNrOfExchangedCards(receivedMessage);
					mainView.setPanelPlayerWhoExchanged();
				}
				break;
			case "09":
//				//Winner announce.
				System.out.println("Winner!: " + receivedMessage);
				switch(receivedMessage.substring(8, 10)) {
				case "WI":
					model.setNumberOfWinners(receivedMessage);
					model.setWinnerID(receivedMessage);
					model.setWinningAmount(receivedMessage);
					if (model.getWinnerID().equals(model.getPlayerID())) {
						model.setPlayerBankrollAfterWinning(Integer.parseInt(model.getWinningAmount()));
					}
					mainView.displayWinner();
					System.out.println("Winner!: Player " + model.getWinnerID() + " won " + model.getWinningAmount() + "T.");
					break;
				case "DR":
					model.setNumberOfWinners(receivedMessage);
					model.setWinnersID(receivedMessage);
					model.setWinningAmount(receivedMessage);
					for(int i=0; i<model.getNumberOfWinners(); i++){
						String winnerID = model.getWinnersID().substring(i, i+1);
						if(winnerID.equals(model.getPlayerID())) {
							model.setPlayerBankrollAfterWinning(Integer.parseInt(model.getWinningAmount()));
						}
					}
					mainView.displayWinner();
					System.out.println("Winners!: Players " + model.getWinnersID() + " won " + model.getWinningAmount() + "T.");
					break;
				}
				break;
			case "10":
//				//next round?
				System.out.println("aaa Next round?: " + receivedMessage);
				switch(receivedMessage.substring(8, 10)) {
				case "AR":
					mainView.askClientForNextRound();
					break;
				case "LO":
					model.setLooserID(receivedMessage);
					mainView.informUserThatSbLoose();
					break;
				case "SN":
					mainView.informUserThatThereWillNotBeAnotherRound();
					break;
				}
				break;
			case "30":
				//Errors
				System.out.println("aaa ERROR: " + receivedMessage);
				switch(receivedMessage.substring(8, 10)) {
				case "01":
					startView.displayMessage("Client, send this message once again, please.");
					mainView.displayMessage("Client, send this message once again, please.");
					break;
				case "02":
					startView.displayMessage("EPIC FAILURE.  Don't be afraid - the Server will create a new Room, and will be joined them automatically.");
					mainView.displayMessage("EPIC FAILURE. Don't be afraid - the Server will create a new Room, and will be joined them automatically.");
					break;
				}
				break;
			}

		} catch (ConnectionFailureException e) {
			startView.informUserOfFailedConnection();
		}
	}

	/**
	 * Method which launch if user pressed button in StartViewJFrame.
	 */
	@Override
	public void updateFromStartView() {
		switch (model.getPressedButton()) {
		case "Connect":
			try {
				core.connectToServer(model.getHost(), model.getPort());
				startView.changeConnectButtonToDisconnect();
				model.setOperationCode(core.checkOperationCode());
				core.getMessage((Notificable) this);
				if (model.getOperationCode().equals("01")) {
					model.setParameters(core.getParameters());
					System.out.println("PlayerID: " + model.getPlayerID());
				} else if (model.getOperationCode().equals("30")) {
					startView.changeDisconnectButtonToConnect();
				}
				model.setText(core.getMessageToDisplay());
			} catch (ConnectionFailureException e) {
				startView.informUserOfFailedConnection();
			}
			break;
		case "Disconnect":
			try {
				model.setMessageToServer("<" + model.getPlayerID() + "><00><>");
				core.sendMessage(model.getMessageToServer());
				core.stopListen();
				System.out.println("Disconnecting...");
				startView.changeDisconnectButtonToConnect();
				model.setText(core.disconnectFromServer());
				System.out.println("Disconnected.");
			} catch (ConnectionFailureException e) {
				// Even if disconnection failure occurs connection will be lost.
				// Anyway we shouldn't inform user of disconnection failure.
			}
			break;
		case "Start Game":
			core.sendMessage(model.getMessageToServer());
			startView
					.displayMessage("Waiting for other players to start game.");
			mainView.createGame();
			// NA POTRZEBY SZYBSZEGO TESTOWANIA
			startView.setVisible(false);
			mainView.setVisible(true);
		}
	}

	/**
	 * Method which launch if user pressed button in MainViewJFrame.
	 */
	@Override
	public void updateFromMainView() {
		switch (model.getPressedButton()) {
		case "Check":
			model.setMessageToServer("<" + model.getPlayerID() + "><06><CH,0>");
			core.sendMessage(model.getMessageToServer());
			System.out.println("aaa zalicytowano check: " + model.getMessageToServer());
			mainView.disableBettingButtons();
			break;
		case "Bet":
			model.setMessageToServer("<" + model.getPlayerID() + "><06><BE," + model.getBetValue() +">");
			core.sendMessage(model.getMessageToServer());
			System.out.println("aaa zalicytowano bet: " + model.getMessageToServer());
			mainView.disableBettingButtons();
			break;
		case "Raise":
			model.setMessageToServer("<" + model.getPlayerID() + "><06><RA," + model.getRaiseValue() +">");
			core.sendMessage(model.getMessageToServer());
			System.out.println("aaa zalicytowano raise: " + model.getMessageToServer());
			mainView.disableBettingButtons();
			break;
		case "Call":
			model.setMessageToServer("<" + model.getPlayerID() + "><06><CA," + model.getCallValue() +">");
			core.sendMessage(model.getMessageToServer());
			System.out.println("aaa zalicytowano call: " + model.getMessageToServer());
			mainView.disableBettingButtons();
			break;
		case "Fold":
			model.setMessageToServer("<" + model.getPlayerID() + "><06><FO,0>");
			core.sendMessage(model.getMessageToServer());
			System.out.println("aaa zalicytowano fold: " + model.getMessageToServer());
			mainView.disableBettingButtons();
			break;
		case "All-in":
			model.setMessageToServer("<" + model.getPlayerID() + "><06><AL," + model.getPlayerBankrollNow() +">");
			core.sendMessage(model.getMessageToServer());
			System.out.println("aaa zalicytowano all-in: " + model.getMessageToServer());
			mainView.disableBettingButtons();
			break;
			
		case "CARD 0":
			model.setNrOfSelectedCards(model.getNrOfSelectedCards() + 1);
			model.setIndexOfSelectedCards(",0");
			mainView.setCard0Selected();
			mainView.displayMessage("Selected cards: "
					+ model.getNrOfSelectedCards());
			break;
		case "CARD 1":
			model.setNrOfSelectedCards(model.getNrOfSelectedCards() + 1);
			model.setIndexOfSelectedCards(",1");
			mainView.setCard1Selected();
			mainView.displayMessage("Selected cards: "
					+ model.getNrOfSelectedCards());
			break;
		case "CARD 2":
			model.setNrOfSelectedCards(model.getNrOfSelectedCards() + 1);
			model.setIndexOfSelectedCards(",2");
			mainView.setCard2Selected();
			mainView.displayMessage("Selected cards: "
					+ model.getNrOfSelectedCards());
			break;
		case "CARD 3":
			model.setNrOfSelectedCards(model.getNrOfSelectedCards() + 1);
			model.setIndexOfSelectedCards(",3");
			mainView.setCard3Selected();
			mainView.displayMessage("Selected cards: "
					+ model.getNrOfSelectedCards());
			break;
		case "Exchange":
			model.setMessageToServer("<" + model.getPlayerID() + "><08><"
					+ model.getNrOfSelectedCards()
					+ model.getIndexOfSelectedCards() + ">");
			core.sendMessage(model.getMessageToServer());
			System.out.println("<" + model.getPlayerID() + "><08><"
					+ model.getNrOfSelectedCards()
					+ model.getIndexOfSelectedCards() + ">");
			model.forgetAboutSelection();
			mainView.disableCardExchange();
			break;
		case "YES":
			mainView.setMainViewToDefault();
			model.setModelToDefault();
			core.sendMessage("<0><10><Y>");
			break;
		case "NO":
			core.sendMessage("<0><10><N>");
			core.stopListen();
			System.exit(0);
			break;
		case "OK":
			core.stopListen();
			System.exit(0);
			break;
		}
	}

	/**
	 * Method which throws ConnectionFailureException from Thread
	 * serverListener.
	 */
	@Override
	public void connectionFailureExceptionOccured() {
		// occurs always when we interrupt Thread
		// startView.informUserOfFailedConnection();
	}

	/**
	 * Method which throws NullPointerException from Thread serverListener.
	 */
	@Override
	public void nullPointerExceptionOccured() {
		startView.informUserOfFailedConnection();
	}
}
